package com.novunda.platform.services;

import com.google.common.collect.Lists;
import com.novunda.platform.common.context.SpringContextHolder;
import com.novunda.platform.common.utils.UserUtils;
import com.novunda.platform.entities.Menu;
import com.novunda.platform.repositories.MenuRepository;
import com.novunda.platform.security.CommonAuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author linfeng
 * @since 2016/8/29
 */
@Service
@Transactional
public class MenuService {

    @Autowired
    private MenuRepository menuRepository;

    private List<CommonAuthorizingRealm> systemRealm;

    public List<Menu> findAllList() {
        return menuRepository.findAllList();
    }

    @Transactional
    public Menu saveOnce(Menu menu) {
        menu.setParentIds(menu.getParent().getParentIds() + menu.getParent().getId() + ",");
        return menuRepository.save(menu);
    }

    @Transactional
    public List<Menu> saveMultiMenu(Iterable<Menu> menu) {
        return menuRepository.save(menu);
    }

    public Menu getMenu(Long id) {
        return menuRepository.findOne(id);
    }

    public List<Menu> findAllMenu(){
        return UserUtils.getMenuList();
    }

    @Transactional(readOnly = false)
    public Menu saveMenu(Menu menu) {
        menu.setParent(getMenu(menu.getParent().getId()));
        String oldParentIds = menu.getParentIds(); // 获取修改前的parentIds，用于更新子节点的parentIds
        menu.setParentIds(menu.getParent().getParentIds() + menu.getParent().getId() + ",");
        Menu m = menuRepository.save(menu);
        // 更新子节点 parentIds
        List<Menu> list = menuRepository.findByParentIdsLike("%,"+menu.getId()+",%");
        for (Menu e : list){
            e.setParentIds(e.getParentIds().replace(oldParentIds, menu.getParentIds()));
        }
        menuRepository.save(list);
        menuRepository.flush();
        clearAllCachedAuthorizationInfo();
        // 清空菜单缓存
        cleanMenuCache();
        return m;
    }

    @Transactional(readOnly = false)
    public void deleteMenu(Long id) {
        menuRepository.deleteById(id, "%," + id + ",%");
        clearAllCachedAuthorizationInfo();
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
    }

    private void cleanMenuCache() {
        UserUtils.removeCache(UserUtils.CACHE_MENU_LIST);
        UserUtils.removeCache(UserUtils.CACHE_HORIZANTAL_MENU_LIST);
    }
    
    public Menu findByParentsIdAndNameAndPermission(long id, String name, String permisson) {
    	return menuRepository.findByParentsIdAndNameAndPermission("%," + id + ",%", name, permisson);
    }
    
    public Menu findByName(String name) {
    	return menuRepository.findByName(name);
    }


    private List<CommonAuthorizingRealm> getAuthorizingRealm() {
        if (systemRealm == null) {
            systemRealm = Lists.newArrayList();
            DefaultWebSecurityManager securityManager = SpringContextHolder.getBean("securityManager");
            for (Realm realm : securityManager.getRealms()) {
                systemRealm.add((CommonAuthorizingRealm) realm);
            }
        }
        return systemRealm;
    }

    private void clearAllCachedAuthorizationInfo() {
        for (CommonAuthorizingRealm realm : getAuthorizingRealm()) {
            realm.clearAllCachedAuthorizationInfo();
        }
    }

    private void clearCachedAuthorizationInfo(String principal) {
        for (CommonAuthorizingRealm realm : getAuthorizingRealm()) {
            realm.clearCachedAuthorizationInfo(principal);
        }
    }

}
